import type {WL_PttPayload} from "./weila_datas";
import {WL} from "@/proto/weilapb";
import Long from "long";

async function fetchWithTimeout(input: RequestInfo, init?: RequestInit, timeout?: number): Promise<Response> {
    const controller = new AbortController;
    const signal = controller.signal;
    let timerId = null as any;
    const localInit = init ? init : {} as RequestInit;
    localInit.signal = signal;

    console.log('fetch url:', input);

    const timeoutPromise = (localTimeout: any) => {
        return new Promise<Response>((resolve, reject) => {
            timerId = setTimeout(() => {
                console.log(`获取URL:${input}超时`);
                resolve(new Response("timeout", {status: 504, statusText: "timeout"}));
                controller.abort();
            }, localTimeout);
        })};

    const fetchPromise = () => {
        return new Promise<Response>((resolve, reject) => {
            console.log('输入URL', input);
            fetch(input, localInit).then(value => {
                clearTimeout(timerId);
                resolve(value);
            }).catch(reason => {
                console.error('获取失败', reason);
                reject(reason);
            })
        })};

    return Promise.race<Response>([timeoutPromise(timeout ? timeout:30000), fetchPromise()]);
}

function decompositionAudioData(pttData: Uint8Array): WL_PttPayload[] {
    let offset = 0;
    let sizeOfOpusData = 0;
    let codedDataList = [] as WL_PttPayload[];
    let frames = 0, prevFrames = 0;
    let prevOffset = 0;

    while (offset < pttData.length) {
        const flag = pttData[offset];
        offset += 1;

        if (flag & 0x80) {
            const dataView = new DataView(pttData.buffer);
            sizeOfOpusData = dataView.getUint16(1, false) + 1;
            offset += 2;
        } else {
            sizeOfOpusData = pttData[offset] + 1;
            offset += 1;
        }

        offset += (sizeOfOpusData - 1);
        frames++;
        if ((frames + 1) % 25 == 0) {
            const payload = {} as WL_PttPayload;
            payload.frameCount = frames - prevFrames;
            payload.data = new Uint8Array(pttData.slice(prevOffset, offset));
            codedDataList.push(payload);
            prevOffset = offset;
            prevFrames = frames;
        }
    }

    if (prevOffset < offset) {
        const payload = {} as WL_PttPayload;
        payload.frameCount = frames - prevFrames;
        payload.data = new Uint8Array(pttData.slice(prevOffset, offset));
        codedDataList.push(payload);
    }

    return codedDataList;
}

function calculateOpusDataFrame(opusData: Uint8Array): number {
    let offset = 0;
    let sizeOfOpusData = 0;
    let frameCount = 0;

    while (offset < opusData.length) {
        const flag = opusData[offset];
        offset += 1;

        if (flag & 0x80) {
            const dataView = new DataView(opusData.buffer);
            sizeOfOpusData = dataView.getUint16(1, false) + 1;
            offset += 2;
        } else {
            sizeOfOpusData = opusData[offset] + 1;
            offset += 1;
        }
        offset += (sizeOfOpusData - 1);
        frameCount++;
    }

    return frameCount;
}


function getOpusDataListFromPttData(pttData: Uint8Array): Uint8Array[] {
    let offset = 0;
    let sizeOfOpusData = 0;
    let codedDataList = [];

    while (offset < pttData.length) {
        const flag = pttData[offset];
        offset += 1;

        if (flag & 0x80) {
            const dataView = new DataView(pttData.buffer);
            sizeOfOpusData = dataView.getUint16(1, false) + 1;
            offset += 2;
        } else {
            sizeOfOpusData = pttData[offset] + 1;
            offset += 1;
        }

        const codedData = new Uint8Array(sizeOfOpusData);
        codedData[0] = flag;
        codedData.set(pttData.subarray(offset, offset + sizeOfOpusData - 1), 1);
        codedDataList.push(codedData);
        offset += (sizeOfOpusData - 1);
    }

    return codedDataList;
}





function genAliOSSCacheFilename(senderId: number, sessionId: string,
    sessionType: number, fileName: string): string {
    // url format:  /YYYY-MM-DD/[user|group|company]_sessionId/senderId-HH-MM-SS-seq-uploadSeq-extraStr.ext
    // get date str
    let curDate = new Date();

    let dateStr = '' + curDate.getFullYear();
    dateStr += ('-' + (curDate.getMonth() + 1 < 10 ? '0' + (curDate.getMonth() + 1) : (curDate.getMonth() + 1)));
    dateStr += ('-' + (curDate.getDate() < 10 ? '0' + curDate.getDate() : curDate.getDate()));

    // get string str
    let timeStr = '' + (curDate.getHours() < 10 ? '0' + curDate.getHours(): curDate.getHours());
    timeStr += ('-' + (curDate.getMinutes() < 10 ? '0' + curDate.getMinutes(): curDate.getMinutes()));
    timeStr += ('-' + (curDate.getSeconds() < 10 ? '0' + curDate.getSeconds(): curDate.getSeconds()));

    // get user session
    let userStr = 'unknown_';
    switch (sessionType) {
        case WL.Common.SessionType.SESSION_TYPE_CORP_SINGLE:
        case WL.Common.SessionType.SESSION_TYPE_SINGLE: {
            userStr = 'user_' + sessionId;
        }
            break;

        case WL.Common.SessionType.SESSION_TYPE_CORP_GROUP:
        case WL.Common.SessionType.SESSION_TYPE_CORP_GROUP_TMP:
        case WL.Common.SessionType.SESSION_TYPE_GROUP: {
            userStr = 'group_' + sessionId;
        }
            break;

        case WL.Common.SessionType.SESSION_TYPE_SERVICE: {
            userStr = 'company_' + sessionId;
        }
            break;
    }

    let url = '/cache/' + dateStr + '/' + userStr + '/' + timeStr + '-user_' + senderId + '-seq_' + genAliOSSCacheFilename.uploadSeq++;
    let extResult = fileName.match(/\.([a-z0-9]{1,6})$/);
    if (extResult && extResult.length >= 2) {
        url += extResult[0];
    }else {
        url += '.unknown';
    }

    if (genAliOSSCacheFilename.uploadSeq > Number.MAX_VALUE - 100) {
        genAliOSSCacheFilename.uploadSeq = 0;
    }

    return url;
}

genAliOSSCacheFilename.uploadSeq = 0;


function genServiceSessionId(serviceId: number, customerId: number): string {
    return new Long(customerId, serviceId).toString(10)
}

export {fetchWithTimeout, decompositionAudioData, genServiceSessionId,
    getOpusDataListFromPttData, calculateOpusDataFrame, genAliOSSCacheFilename}
